package com.ccrfid.rmc6.resource.poi;

import com.ccrfid.rmc6.appconfig.auth.Secured;
import com.ccrfid.rmc6.appconfig.exception.pojo.AppException;
import com.ccrfid.rmc6.appconfig.exception.pojo.CustomErrors;
import com.ccrfid.rmc6.entity.device.LocatorEntity;
import com.ccrfid.rmc6.entity.poi.PoiLocationEntity;
import com.ccrfid.rmc6.entity.video.VideoCameraView;
import com.ccrfid.rmc6.pojo.dto.*;
import com.ccrfid.rmc6.pojo.param.PageParam;
import com.ccrfid.rmc6.pojo.param.SortParam;
import com.ccrfid.rmc6.repository.search.Criterion;
import com.ccrfid.rmc6.repository.search.SearchCriteria;
import com.ccrfid.rmc6.resource.auth.pojo.UserPrincipal;
import com.ccrfid.rmc6.resource.sse.pojo.SubscribeLocation;
import com.ccrfid.rmc6.service.poi.PoiLocationService;
import com.ccrfid.rmc6.service.poi.PoiService;
import com.ccrfid.rmc6.service.sys.DictService;
import com.ccrfid.rmc6.service.video.VideoSyncService;
import com.ccrfid.rmc6.util.NetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import java.util.ArrayList;
import java.util.List;

@Secured
@Path("locations")
@Produces(MediaType.APPLICATION_JSON)
public class PoiLocationResource {
    private static final Logger logger = LoggerFactory.getLogger(PoiLocationResource.class);
    @Context
    private SecurityContext securityContext;
    @Autowired
    private PoiLocationService poiLocationService;
    @Autowired
    private DictService dictService;
    @Autowired
    private PoiService poiService;
    @Autowired
    private VideoSyncService videoSyncService;
    @Context
    private HttpServletRequest httpServletRequest;

    @GET
    public List<PoiLocationEntity> getPoiLocationList(@QueryParam("locationName") String locationName,
                                                      @QueryParam("mapLevel") Integer mapLevel,
                                                      @QueryParam("floorNumber") Integer floorNumber,
                                                      @QueryParam("locationType") Integer locationType,
                                                      @BeanParam SortParam sortParam) {
        SearchCriteria criteria = SearchCriteria.Builder.create();
        if (locationName != null) {
            criteria.add(new Criterion("locationName", Criterion.Operator.LIKE, '%' + locationName + '%'));
        }
        if (mapLevel != null) {
            criteria.add(new Criterion("mapLevel", Criterion.Operator.EQ, mapLevel));
        }
        if (floorNumber != null) {
            criteria.add(new Criterion("floorNumber", Criterion.Operator.EQ, floorNumber));
        }
        if (locationType != null) {
            criteria.add(new Criterion("locationType", Criterion.Operator.EQ, locationType));
        }
        List<PoiLocationEntity> list;
        if (sortParam.getOrders() != null && sortParam.getOrders().size() > 0) {
            list = poiLocationService.getPoiLocationList(criteria, Sort.by(sortParam.getOrders()));
        } else {
            list = poiLocationService.getPoiLocationList(criteria, Sort.by(new ArrayList<>()));
        }
        return list;
    }

    @GET
    @Path("search")
    public Page<PoiLocationEntity> getPoiLocationPage(@QueryParam("locationName") String locationName,
                                                      @QueryParam("mapLevel") Integer mapLevel,
                                                      @QueryParam("floorNumber") Integer floorNumber,
                                                      @QueryParam("locationType") Integer locationType,
                                                      @BeanParam PageParam pageParam) {
        SearchCriteria criteria = SearchCriteria.Builder.create();
        if (locationName != null) {
            criteria.add(new Criterion("locationName", Criterion.Operator.LIKE, '%' + locationName + '%'));
        }
        if (mapLevel != null) {
            criteria.add(new Criterion("mapLevel", Criterion.Operator.EQ, mapLevel));
        }
        if (floorNumber != null) {
            criteria.add(new Criterion("floorNumber", Criterion.Operator.EQ, floorNumber));
        }
        if (locationType != null) {
            List<Integer> typeList = new ArrayList<>();
            typeList.addAll(dictService.getDictAndSubDictIdListById(locationType));
            criteria.add(new Criterion("locationType", Criterion.Operator.IN, typeList));
        }
        PageRequest pageRequest;
        if (pageParam.getOrders() != null && pageParam.getOrders().size() > 0) {
            pageRequest = PageRequest.of(pageParam.getPageNumber(), pageParam.getPageSize(), Sort.by(pageParam.getOrders()));
        } else {
            pageRequest = PageRequest.of(pageParam.getPageNumber(), pageParam.getPageSize());
        }
        return poiLocationService.getPoiLocationPageList(criteria, pageRequest);
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public PoiLocationEntity createPoiLocation(PoiLocationEntity entity) throws AppException {
        PoiLocationEntity poiLocationEntity = poiLocationService.createPoiLocation(entity);
        return poiLocationEntity;
    }

    @DELETE
    @Consumes(MediaType.APPLICATION_JSON)
    public int deletePoiLocations(List<Long> idList) throws AppException {
        if (idList == null) {
            throw new AppException(Response.Status.BAD_REQUEST.getStatusCode(),
                    CustomErrors.param_is_null.getCode(), CustomErrors.param_is_null.getReason(), "");
        }
        return poiLocationService.deletePoiLocations(idList);
    }

    @GET
    @Path("{id}")
    public PoiLocationEntity getPoiLocationById(@PathParam("id") Long locationId) {
        PoiLocationEntity poiLocationEntity = poiLocationService.getPoiLocationById(locationId);
        return poiLocationEntity;
    }

    @PUT
    @Path("{id}")
    @Consumes(MediaType.APPLICATION_JSON)
    public PoiLocationEntity updatePoiLocation(@PathParam("id") Long locationId, PoiLocationEntity entity)
            throws AppException {
        PoiLocationEntity poiLocationEntity = poiLocationService.updatePoiLocation(locationId, entity);
        return poiLocationEntity;
    }

    @PUT
    @Path("{locationId}/binding/org/{orgId}")
    public PoiLocationEntity bindLocationOrg(@PathParam("locationId") Long locationId,
                                             @PathParam("orgId") Long orgId) throws AppException {
        return poiLocationService.bindLocationOrg(locationId, orgId);
    }

    @DELETE
    @Path("{locationId}/binding")
    public PoiLocationEntity unBindLocationOrg(@PathParam("locationId") Long locationId) throws AppException {
        return poiLocationService.unBindLocationOrg(locationId);
    }

    @GET
    @Path("{locationId}/personnels")
    public Page<LocationPersonnelDto> getPersonnelsInfo(@PathParam("locationId") Long locationId,
                                                        @BeanParam PageParam pageParam) {
        PageRequest pageRequest = PageRequest.of(pageParam.getPageNumber(), pageParam.getPageSize());
        return poiLocationService.getPersonnelsInfoInLocation(locationId, pageRequest);
    }

    @GET
    @Path("{locationId}/actual-personnels")
    public Page<LocationPersonnelDto> getActualPersonnelsInfo(@PathParam("locationId") Long locationId,
                                                                 @QueryParam("personnelType") Integer personnelType,
                                                                 @BeanParam PageParam pageParam) {
        PageRequest pageRequest = PageRequest.of(pageParam.getPageNumber(), pageParam.getPageSize());
        return poiLocationService.getActualPersonnelsInfoInLocation(locationId, personnelType, pageRequest);
    }

    @GET
    @Path("{locationId}/bind-personnels")
    public LocationBindPersonnelDto getBindPersonnelsInfo(@PathParam("locationId") Long locationId) {
        return poiLocationService.getBindPersonnelsInfoInLocation(locationId);
    }

    @GET
    @Path("all/locators")
    public List<LocationLocatorDto> getAllLocationLocators() {
        List<LocationLocatorDto> list = new ArrayList<>();
        List<PoiLocationEntity> locationList = poiLocationService.getAllLocations();
        if (locationList != null && locationList.size() > 0) {
            LocationLocatorDto dto = new LocationLocatorDto();
            for (PoiLocationEntity locationEntity : locationList) {
                dto.setLocation(locationEntity);
                List<LocatorEntity> locatorList = poiService.getLocatorsInLocation(locationEntity);
                dto.setLocatorList(locatorList);
                list.add(dto);
            }
        }
        return list;
    }

    @GET
    @Path("{locationId}/locators")
    public List<LocatorEntity> getLocationLocators(@PathParam("locationId") Long locationId) {
        PoiLocationEntity locationEntity = poiLocationService.getPoiLocationById(locationId);
        if (locationEntity != null) {
            return poiService.getLocatorsInLocation(locationEntity);
        } else {
            return new ArrayList<>();
        }
    }

    @GET
    @Path("{locationId}/linkage-cameras")
    public List<VideoCameraDto> getCamerasInLocation(@PathParam("locationId") Long locationId) {
        UserPrincipal userPrincipal = (UserPrincipal) securityContext.getUserPrincipal();
        Integer cameraPermissionLevel = userPrincipal != null ? userPrincipal.getCameraPermissionLevel() : 3;

        PoiLocationEntity locationEntity = poiLocationService.getPoiLocationById(locationId);
        if (locationEntity == null) {
            return new ArrayList<>();
        }
        String clientIpAddr = httpServletRequest.getRemoteAddr();
        List<VideoCameraView> cameralist = poiService.getCamerasInLocation(locationEntity);

        return getLinkageCameraList(cameralist, cameraPermissionLevel, clientIpAddr);
    }

    @PUT
    @Path("linkage-cameras")
    @Consumes(MediaType.APPLICATION_JSON)
    public List<VideoCameraDto> getCamerasInPolygon(SubscribeLocation sub) {
        UserPrincipal userPrincipal = (UserPrincipal) securityContext.getUserPrincipal();
        Integer cameraPermissionLevel = userPrincipal != null ? userPrincipal.getCameraPermissionLevel() : 3;

        String clientIpAddr = httpServletRequest.getRemoteAddr();
        List<VideoCameraView> cameralist = poiService.getCamerasInPolygon(sub.getFloorNumber(), sub.getPolygon());

        return getLinkageCameraList(cameralist, cameraPermissionLevel, clientIpAddr);
    }

    private List<VideoCameraDto> getLinkageCameraList(List<VideoCameraView> cameralist,
                                                      Integer cameraPermissionLevel, String clientIpAddr) {
        if (cameralist != null && cameralist.size() > 0) {
            List<VideoCameraDto> list = new ArrayList<>();
            for (VideoCameraView cameraView : cameralist) {
                if (cameraPermissionLevel != null && cameraView.getPermissionLevel() >= cameraPermissionLevel) {
                    String ip = NetUtil.getMatchIPAddr(clientIpAddr, cameraView.getIp(), cameraView.getIp2());
                    VideoCameraDto dto = new VideoCameraDto();
                    dto.setRescode(cameraView.getCameraSn());
                    dto.setName(cameraView.getCameraName());
                    dto.setVersion(videoSyncService.getIVersion(cameraView.getCameraVersion()));
                    dto.setIp(ip);
                    dto.setPort(cameraView.getPort());
                    dto.setUsername(cameraView.getUsername());
                    dto.setPassword(cameraView.getPasswd());
                    dto.setChannel(cameraView.getChannelNum());
                    dto.setCameraId(cameraView.getId());
                    list.add(dto);
                }
            }
            return list;
        }
        return new ArrayList<>();
    }

}
